﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace csharp_crypt
{
    class Program
    {
        const String AESKEY = "abcdefghijklmnopqrstuvwxyz123456"; // 32 byte
        const String SEED128KEY = "abcdefghijklmnop"; // 16 byte
        const String TRIPLEDESKEY = "abcdefghijklmnopqrstuvwx"; // 24byte

        const int AESBLOCKSIZE = 16;
        const int AESIVSIZE = 16;
        const int TRIPLEDESBLOCKSIZE = 8;
        const int TRIPLEDESIVSIZE = 8;
        
        static void Main(string[] args)
        {
            ConsoleKeyInfo consoleKeyInfo;

            do
            {
                fnPrintMode();
                consoleKeyInfo = Console.ReadKey();
                Console.WriteLine();

                switch(consoleKeyInfo.Key)
                {
                    case ConsoleKey.D1:
                    case ConsoleKey.NumPad1:
                        fnSha256Mode();
                        break;
                    case ConsoleKey.D2:
                    case ConsoleKey.NumPad2:
                        fnAes256Mode();
                        break;
                    case ConsoleKey.D3:
                    case ConsoleKey.NumPad3:
                        fnSeed128CbcMode();
                        break;
                    case ConsoleKey.D4:
                    case ConsoleKey.NumPad4:
                        fn3DesMode();
                        break;
                }
            } while (consoleKeyInfo.Key != ConsoleKey.Q);
        }

        static void fnPrintMode()
        {
            Console.WriteLine("1. sha256");
            Console.WriteLine("2. aes256");
            Console.WriteLine("3. seed128cbc");
            Console.WriteLine("4. 3des");
            Console.WriteLine("q. quit");
        }

        static void fn3DesMode()
        {
            Console.Write("input text: ");
            String input_text = Console.ReadLine();

            byte[] iv = Enumerable.Repeat((byte)0x00, TRIPLEDESIVSIZE).ToArray();

            byte[] encrypt = fn3DesEncrypt(Encoding.UTF8.GetBytes(input_text), Encoding.UTF8.GetBytes(TRIPLEDESKEY), iv);
            byte[] decrypt = fn3DesDecrypt(encrypt, Encoding.UTF8.GetBytes(TRIPLEDESKEY), iv);

            Console.WriteLine(Convert.ToBase64String(encrypt));
            Console.WriteLine(Encoding.UTF8.GetString(decrypt));
        }

        static byte[] fn3DesEncrypt(byte[] decrypt, byte[] key, byte[] iv)
        {
            TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
            tripleDESCryptoServiceProvider.KeySize = key.Length * 8;
            tripleDESCryptoServiceProvider.BlockSize = TRIPLEDESBLOCKSIZE * 8;
            tripleDESCryptoServiceProvider.Mode = CipherMode.CBC;
            tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
            tripleDESCryptoServiceProvider.Key = key;
            tripleDESCryptoServiceProvider.IV = iv;

            ICryptoTransform iCryptoTransform = tripleDESCryptoServiceProvider.CreateEncryptor();
            byte[] rtn;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(decrypt, 0, decrypt.Length);
                    cryptoStream.FlushFinalBlock();
                }

                rtn = memoryStream.ToArray();
            }

            return rtn;
        }

        static byte[] fn3DesDecrypt(byte[] encrypt, byte[] key, byte[] iv)
        {
            TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
            tripleDESCryptoServiceProvider.KeySize = key.Length * 8;
            tripleDESCryptoServiceProvider.BlockSize = TRIPLEDESBLOCKSIZE * 8;
            tripleDESCryptoServiceProvider.Mode = CipherMode.CBC;
            tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
            tripleDESCryptoServiceProvider.Key = key;
            tripleDESCryptoServiceProvider.IV = iv;

            ICryptoTransform iCryptoTransform = tripleDESCryptoServiceProvider.CreateDecryptor();
            byte[] rtn;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(encrypt, 0, encrypt.Length);
                    cryptoStream.FlushFinalBlock();
                }

                rtn = memoryStream.ToArray();
            }

            return rtn;
        }

        static void fnSeed128CbcMode()
        {
            Console.Write("input text: ");
            String input_text = Console.ReadLine();

            byte[] iv = Enumerable.Repeat((byte)0x00, KISA_SEED_CBC.IVSIZE).ToArray();

            byte[] encrypt = fnSeed128CbcEncrypt(Encoding.UTF8.GetBytes(input_text), Encoding.UTF8.GetBytes(SEED128KEY), iv);
            byte[] decrypt = fnSeed128CbcDecrypt(encrypt, Encoding.UTF8.GetBytes(SEED128KEY), iv);

            Console.WriteLine(Convert.ToBase64String(encrypt));
            Console.WriteLine(Encoding.UTF8.GetString(decrypt));
        }

        static byte[] fnSeed128CbcEncrypt(byte[] decrypt, byte[] key, byte[] iv)
        {
            return KISA_SEED_CBC.Encrypt(decrypt, key, iv);
        }

        static byte[] fnSeed128CbcDecrypt(byte[] encrypt, byte[] key, byte[] iv)
        {
            return KISA_SEED_CBC.Decrypt(encrypt, key, iv);
        }

        static void fnAes256Mode()
        {
            Console.Write("input text: ");
            String input_text = Console.ReadLine();

            byte[] iv = Enumerable.Repeat((byte)0x00, AESIVSIZE).ToArray();
            

            byte[] encrypt = fnAes256Encrypt(Encoding.UTF8.GetBytes(input_text), Encoding.UTF8.GetBytes(AESKEY), iv);
            byte[] decrypt = fnAes256Decrypt(encrypt, Encoding.UTF8.GetBytes(AESKEY), iv);

            Console.WriteLine(Convert.ToBase64String(encrypt));
            Console.WriteLine(Encoding.UTF8.GetString(decrypt));
        }

        static byte[] fnAes256Encrypt(byte[] decrypt, byte[] key, byte[] iv)
        {
            RijndaelManaged aes = new RijndaelManaged();
            aes.KeySize = key.Length * 8;
            aes.BlockSize = AESBLOCKSIZE * 8;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = key;
            aes.IV = iv;

            ICryptoTransform iCryptoTransform = aes.CreateEncryptor();
            byte[] rtn;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(decrypt, 0, decrypt.Length);
                    cryptoStream.FlushFinalBlock();
                }

                rtn = memoryStream.ToArray();
            }

            return rtn;
        }

        static byte[] fnAes256Decrypt(byte[] encrypt, byte[] key, byte[] iv)
        {
            RijndaelManaged aes = new RijndaelManaged();
            aes.KeySize = key.Length * 8;
            aes.BlockSize = AESBLOCKSIZE * 8;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = key;
            aes.IV = iv;

            ICryptoTransform iCryptoTransform = aes.CreateDecryptor();
            byte[] rtn;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(encrypt, 0, encrypt.Length);
                    cryptoStream.FlushFinalBlock();
                }

                rtn = memoryStream.ToArray();
            }

            return rtn;
        }

        static void fnSha256Mode()
        {
            Console.Write("input text: ");
            String input_text = Console.ReadLine();

            byte[] encrypt = fnSha256Encrypt(Encoding.UTF8.GetBytes(input_text));

            Console.WriteLine(Convert.ToBase64String(encrypt));
        }

        static byte[] fnSha256Encrypt(byte[] decrypt)
        {
            SHA256 sha256 = new SHA256Managed();
            return sha256.ComputeHash(decrypt);
        }
    }
}
